using System;
using System.Collections.Generic;
using System.Net.Sockets;
using UnityEngine;

namespace IQIGame.Onigao.Framework
{
    [DisallowMultipleComponent]
    public class NetworkManager : FrameMonoModule
    {
        private Dictionary<string, NetworkChannel> m_NetworkChannels;

        public event Action<INetworkChannel> NetworkClosedEventHandler;
        public event Action<INetworkChannel, int> NetworkMissHeartBeatEventHandler;
        public event Action<INetworkChannel, NetworkErrorCode, SocketError, string, object> NetworkErrorEventHandler;
        public event Action<INetworkChannel, object> NetworkCustomErrorEventHandler;

        protected override void OnInit()
        {
            m_NetworkChannels = new Dictionary<string, NetworkChannel>();

            NetworkClosedEventHandler = null;
            NetworkMissHeartBeatEventHandler = null;
            NetworkErrorEventHandler = null;
            NetworkCustomErrorEventHandler = null;

            FrameworkEntry.MonoDriver.updateEvent += OnUpdate;
        }

        private void OnUpdate(float deltaTime, float unScaledDeltaTime)
        {
            foreach (var kv in m_NetworkChannels)
            {
                kv.Value.Update(deltaTime, unScaledDeltaTime);
            }
        }

        protected override void OnEnterGame()
        {

        }

        /// <summary>
        /// 检查是否存在网络频道。
        /// </summary>
        /// <param name="name">网络频道名称。</param>
        /// <returns>是否存在网络频道。</returns>
        public bool HasNetworkChannel(string name)
        {
            return m_NetworkChannels.ContainsKey(name ?? string.Empty);
        }

        /// <summary>
        /// 获取网络频道。
        /// </summary>
        /// <param name="name">网络频道名称。</param>
        /// <returns>要获取的网络频道。</returns>
        public INetworkChannel GetNetworkChannel(string name)
        {
            NetworkChannel networkChannel = null;
            if (m_NetworkChannels.TryGetValue(name ?? string.Empty, out networkChannel))
            {
                return networkChannel;
            }

            return null;
        }

        /// <summary>
        /// 获取所有网络频道。
        /// </summary>
        /// <returns>所有网络频道。</returns>
        public INetworkChannel[] GetAllNetworkChannels()
        {
            int index = 0;
            INetworkChannel[] results = new INetworkChannel[m_NetworkChannels.Count];
            foreach (KeyValuePair<string, NetworkChannel> networkChannel in m_NetworkChannels)
            {
                results[index++] = networkChannel.Value;
            }

            return results;
        }

        /// <summary>
        /// 获取所有网络频道。
        /// </summary>
        /// <param name="results">所有网络频道。</param>
        public void GetAllNetworkChannels(List<INetworkChannel> results)
        {
            if (results == null)
            {
                throw new FrameworkException("Results is invalid.");
            }

            results.Clear();
            foreach (KeyValuePair<string, NetworkChannel> networkChannel in m_NetworkChannels)
            {
                results.Add(networkChannel.Value);
            }
        }

        /// <summary>
        /// 创建网络频道。
        /// </summary>
        /// <param name="name">网络频道名称。</param>
        /// <param name="networkChannelHelper">网络频道辅助器。</param>
        /// <returns>要创建的网络频道。</returns>
        public INetworkChannel CreateNetworkChannel(string name, INetworkChannelHelper networkChannelHelper)
        {
            if (networkChannelHelper == null)
            {
                throw new FrameworkException("Network channel helper is invalid.");
            }

            if (networkChannelHelper.PacketHeaderLength < 0)
            {
                throw new FrameworkException("Packet header length is invalid.");
            }

            if (HasNetworkChannel(name))
            {
                throw new FrameworkException(string.Format("Already exist network channel '{0}'.", name ?? string.Empty));
            }

            NetworkChannel networkChannel = new NetworkChannel(name, networkChannelHelper);
            networkChannel.NetworkChannelClosed += OnNetworkChannelClosed;
            networkChannel.NetworkChannelMissHeartBeat += OnNetworkChannelMissHeartBeat;
            networkChannel.NetworkChannelError += OnNetworkChannelError;
            networkChannel.NetworkChannelCustomError += OnNetworkChannelCustomError;
            m_NetworkChannels.Add(name, networkChannel);
            return networkChannel;
        }

        /// <summary>
        /// 销毁网络频道。
        /// </summary>
        /// <param name="name">网络频道名称。</param>
        /// <returns>是否销毁网络频道成功。</returns>
        public bool DestroyNetworkChannel(string name)
        {
            NetworkChannel networkChannel = null;
            if (m_NetworkChannels.TryGetValue(name ?? string.Empty, out networkChannel))
            {
                networkChannel.NetworkChannelClosed -= OnNetworkChannelClosed;
                networkChannel.NetworkChannelMissHeartBeat -= OnNetworkChannelMissHeartBeat;
                networkChannel.NetworkChannelError -= OnNetworkChannelError;
                networkChannel.NetworkChannelCustomError -= OnNetworkChannelCustomError;
                networkChannel.Shutdown();
                return m_NetworkChannels.Remove(name);
            }

            return false;
        }

        private void OnNetworkChannelClosed(NetworkChannel networkChannel)
        {
            if (NetworkClosedEventHandler != null)
            {
                lock (NetworkClosedEventHandler)
                {
                    NetworkClosedEventHandler(networkChannel);
                }
            }
        }

        private void OnNetworkChannelMissHeartBeat(NetworkChannel networkChannel, int missHeartBeatCount)
        {
            if (NetworkMissHeartBeatEventHandler != null)
            {
                lock (NetworkMissHeartBeatEventHandler)
                {
                    NetworkMissHeartBeatEventHandler(networkChannel, missHeartBeatCount);
                }
            }
        }

        private void OnNetworkChannelError(NetworkChannel networkChannel, NetworkErrorCode errorCode, SocketError socketErrorCode, string errorMessage, object userData)
        {
            if (NetworkErrorEventHandler != null)
            {
                lock (NetworkErrorEventHandler)
                {
                    NetworkErrorEventHandler(networkChannel, errorCode, socketErrorCode, errorMessage, userData);
                }
            }
        }

        private void OnNetworkChannelCustomError(NetworkChannel networkChannel, object customErrorData)
        {
            if (NetworkCustomErrorEventHandler != null)
            {
                lock (NetworkCustomErrorEventHandler)
                {
                    NetworkCustomErrorEventHandler(networkChannel, customErrorData);
                }
            }
        }

        protected override void OnShutdown()
        {
            foreach (var kv in m_NetworkChannels)
            {
                kv.Value.Dispose();
            }
            m_NetworkChannels.Clear();
            NetworkClosedEventHandler = null;
            NetworkMissHeartBeatEventHandler = null;
            NetworkErrorEventHandler = null;
            NetworkCustomErrorEventHandler = null;
        }
    }
}
